package com.example.kehoobackend.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.example.kehoobackend.common.CommonResponse;
import com.example.kehoobackend.common.FilterUserType;
import com.example.kehoobackend.common.FollowType;
import com.example.kehoobackend.domain.DayInfo;
import com.example.kehoobackend.domain.Follow;
import com.example.kehoobackend.domain.User;
import com.example.kehoobackend.persistance.FollowMapper;
import com.example.kehoobackend.persistance.UserMapper;
import com.example.kehoobackend.service.DayInfoService;
import com.example.kehoobackend.service.EmailService;
import com.example.kehoobackend.service.FollowService;
import com.example.kehoobackend.service.UserService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Lazy;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;
import org.springframework.util.DigestUtils;

import java.time.LocalDate;
import java.util.*;
import java.util.stream.Collectors;

@Service("userService")
public class UserServiceImpl extends ServiceImpl<UserMapper, User> implements UserService {

    @Autowired
    private RedisTemplate redisTemplate;

    @Autowired
    private EmailService emailService;

    @Lazy
    @Autowired
    private FollowService followService;

    @Autowired
    private FollowMapper followMapper;

    @Lazy
    @Autowired
    private DayInfoService dayInfoService;


    @Override
    public CommonResponse<Map> login(String username, String password) {
        QueryWrapper<User> queryWrapper = new QueryWrapper<>();
        queryWrapper.eq("username",username);
        User user = getOne(queryWrapper);

        if(user == null){
            return CommonResponse.createForError("用户名不存在");
        }else if(user.getPassword().equals(getMD5Password(password,user.getSalt()))) {
            Map<String, Object> map = new HashMap<>();
            user.setPassword(null);
            String token = UUID.randomUUID().toString();

            //清除之前的token
            redisTemplate.delete(user.getId()+"token");
            //向redis中添加token缓存，标识为id+"token"
            redisTemplate.opsForValue().set(user.getId()+"token",token);

            map.put("User",user);
            map.put("token",token);

            return CommonResponse.createForSuccess("登录成功！",map);
        }else {
            return CommonResponse.createForError("密码错误！");
        }
    }

    @Override
    public boolean usernameIsExist(String username) {
        QueryWrapper<User> queryWrapper = new QueryWrapper<>();
        queryWrapper.eq("username",username);
        User user = getOne(queryWrapper);

        return user == null;
    }

    @Override
    public boolean register(User user,String token, String code) {
        if(!usernameIsExist(user.getUsername()))return false;
        else if(!emailIsExist(user.getEmail()))return false;
        else {
            if(emailService.verifyCode(token,code)){
                encodePassword(user);
                save(user);
                redisTemplate.delete(token);

                //今日新增用户数加1
                String currentDate = String.valueOf(LocalDate.now());
                DayInfo dayInfo = dayInfoService.getById(currentDate);
                dayInfo.setNew_users_count(dayInfo.getNew_users_count()+1);
                dayInfoService.updateById(dayInfo);

                return true;
            }
            else return false;
        }
    }

    @Override
    public boolean changePassword(Integer user_id,String password) {
        User user = getById(user_id);
        user.setPassword(password);
        encodePassword(user);
        return updateById(user);
    }

    @Override
    public boolean emailIsExist(String email) {
        QueryWrapper<User> queryWrapper = new QueryWrapper<>();
        queryWrapper.eq("email",email);
        User user = getOne(queryWrapper);

        return user == null;
    }

    @Override
    public boolean changeEmail(Integer user_id,String email,String token,String code) {
        if(emailService.verifyCode(token,code)){
            User user = getById(user_id);
            user.setEmail(email);
            return updateById(user);
        }
        else return false;
    }

    @Override
    public boolean deleteUser(Integer user_id) {
        removeById(user_id);

        //将该用户从所有关注了该用户的用户关注列表中移除
        QueryWrapper<Follow> queryWrapper = new QueryWrapper<>();
        queryWrapper.eq("to_id",user_id).eq("type",FollowType.USER);
        List<Follow> followList = followService.list(queryWrapper);
        for(Follow follow : followList){
            followService.removeById(follow);
        }


        return true;
    }

    @Override
    public CommonResponse<List<User>> recommendUser(Integer user_id) {
        //TODO:按关注的问题，话题返回推荐用户
        //目前返回粉丝最多的用户
        QueryWrapper<Follow> followQueryWrapper = new QueryWrapper<>();
        followQueryWrapper.select("to_id").eq("type",FollowType.USER)
                .groupBy("to_id")
                .orderByDesc("count(*)");

        List<Map<String, Object>> resultList = followMapper.selectMaps(followQueryWrapper);

        List<Integer> toIdList = resultList.stream()
                .map(map -> (Integer) map.get("to_id"))
                .collect(Collectors.toList());

//        System.out.println(toIdList);

        List<User> recommendedUsers = new ArrayList<>();
        for(Integer integer : toIdList){
            boolean is_follow = followService.isFollow(user_id,integer,FollowType.USER);
            //排除已关注的用户和自身
            if(!is_follow && integer.intValue()!=user_id.intValue()){
                User user = getById(integer);
                recommendedUsers.add(user);
                if(recommendedUsers.size() == 12){
                    break;
                }
            }
        }

        return CommonResponse.createForSuccess("推荐用户",recommendedUsers);
    }

    @Override
    public CommonResponse<User> getUserInfo(Integer user_id) {
        User user = getById(user_id);
        return CommonResponse.createForSuccess("根据ID查询用户",user);
    }

    @Override
    public boolean logout(Integer user_id) {
        return redisTemplate.delete(user_id+"token");
    }

    @Override
    public boolean changePasswordByEmail(Integer userId, String password, String email, String token, String code) {
        if(emailService.verifyCode(token,code)){
            User user = getById(userId);
            user.setPassword(password);
            encodePassword(user);
            return updateById(user);
        }
        else return false;
    }

    @Override
    public CommonResponse<Map> faceLogin(Integer user_id) {
        Map<String, Object> map = new HashMap<>();
        String token = UUID.randomUUID().toString();

        User user = getById(user_id);

        //清除之前的token
        redisTemplate.delete(user_id+"token");
        //向redis中添加token缓存，标识为id+"token"
        redisTemplate.opsForValue().set(user_id+"token",token);

        map.put("User",user);
        map.put("token",token);

        return CommonResponse.createForSuccess("人脸识别登录",map);
    }

    @Override
    public CommonResponse<List<User>> searchUser(String keyword,Integer user_id) {
        QueryWrapper<User> queryWrapper = new QueryWrapper<>();
        queryWrapper.like("username",keyword).ne("user_id",user_id);
        List<User> userList = list(queryWrapper);
        for (User user : userList){
            user.setFollowed(followService.isFollow(user_id,user.getId(),FollowType.USER));
        }


        return CommonResponse.createForSuccess("根据用户名查询用户",userList);
    }

    @Override
    public User getUserByUsername(String username) {
        QueryWrapper<User> queryWrapper = new QueryWrapper<>();
        queryWrapper.eq("username",username).select("user_id","username");
        return getOne(queryWrapper);
    }

    @Override
    public CommonResponse<List<User>> getAllUserInfo() {
        return CommonResponse.createForSuccess("返回所有用户列表",list());
    }

    @Override
    public CommonResponse<List<User>> filterUser(Integer type, String value) {

        List<User> filterUsers = null;
        QueryWrapper<User> queryWrapper = new QueryWrapper<>();
        switch (type){
            case FilterUserType.GENDER :
                queryWrapper.eq("gender",Integer.parseInt(value));
                filterUsers = list(queryWrapper);
                break;
            case FilterUserType.USERNAME:
                queryWrapper.eq("username",value);
                filterUsers = list(queryWrapper);
                break;
            case FilterUserType.POSITION:
                queryWrapper.eq("position",value);
                filterUsers = list(queryWrapper);
                break;
            case FilterUserType.INDUSTRY:
                queryWrapper.eq("industry",value);
                filterUsers = list(queryWrapper);
                break;
        }

        return CommonResponse.createForSuccess("按条件查询用户",filterUsers);
    }

    @Override
    public boolean resetUserPassword(Integer user_id) {
        //将指定用户密码重置为123456
        User user = getById(user_id);
        user.setPassword("123456");
        encodePassword(user);
        return updateById(user);
    }

    @Override
    public boolean verifyPassword(int user_id, String password) {
        User user = getById(user_id);
        return user.getPassword().equals(getMD5Password(password,user.getSalt()));
    }

    @Override
    public boolean updateUserInfo(User user) {
        return updateById(user);
    }

    //加密MD5
    public void encodePassword(User user) {
        String oldPassword = user.getPassword();
        String salt = UUID.randomUUID().toString().toUpperCase();
        user.setSalt(salt);
        String md5Password = getMD5Password(oldPassword, salt);
        user.setPassword(md5Password);
    }


    private String getMD5Password(String password,String salt){
        for (int i = 0;i <3; i++){
            //md5加密算法方法的调用(进行三次加密)
            password = DigestUtils.md5DigestAsHex((salt+password+salt).getBytes()).toUpperCase();
        }
        //返回加密后的密码
        return password;
    }


}
